package es.us.idinfor;

import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.jgrapht.Graph;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import es.us.idinfor.graph.Edge;
import es.us.idinfor.graph.Vertex;

public class Episode {
	private String id;
	private List<Set<Event>> graph = null;
	private List<Window> windows = null;
	
	public Episode(String name) {
		id = name;
		graph = Lists.newLinkedList();
		windows = Lists.newLinkedList();
	}
	
	public String getId() {
		return id;
	}
	
	public List<Set<Event>> getGraph() {
		return graph;
	}
	
	public void setWindows(List<Window> ws) {
		windows.clear();
		windows.addAll(ws);
	}
	
	public int size() {
		return graph.size();
	}
	
	public List<Set<Event>> getInvertedGraph() {
		List<Set<Event>> res = Lists.newLinkedList();
		
		for(Set<Event> events: graph) {
			res.add(0, events);
		}
		
		return res;
	}
	
	public boolean isEmpty() {
		return graph.isEmpty();
	}
	
	public void addTemporalConstraints(Graph<Vertex, Edge> g) {
		List<Vertex> nodes = Lists.newArrayList(g.vertexSet());
		Vertex vertexInf = null;
		Vertex vertexSup = null;
		Event eventInf = null;
		Event eventSup = null;
		long diff = 0;
		int inf = 0;
		int sup = 1;
		
		Collections.sort(nodes);
				
		for(Window w: windows) {
			inf = 0;
			sup = 1;
			
			while(sup < nodes.size()) {
				vertexInf = nodes.get(inf);
				vertexSup = nodes.get(sup);
				
				if(vertexInf.getPos() != vertexSup.getPos()) {
					eventInf = w.getEvents().get(vertexInf.getPos());
					eventSup = w.getEvents().get(vertexSup.getPos());
					
					if(eventInf.getId().equals(vertexInf.getId()) && eventSup.getId().equals(vertexSup.getId())) {
						diff = eventSup.getTimeStamp() - eventInf.getTimeStamp();
						
						if(g.getEdge(vertexInf, vertexSup).getDuration() < diff) {
							g.removeEdge(vertexInf, vertexSup);
							g.addEdge(vertexInf, vertexSup, new Edge(diff));
						}
						
						inf++;
						sup++;
					}
					else {
						if((sup - inf) > 1) {
							inf++;
						}
						else {
							sup++;
						}
					}
				}
				else {
					sup++;
				}
			}
		}
		
		eventSup = null;
		eventInf = null;
		vertexSup = null;
		vertexInf = null;
	}
	
	public void addSerial(Event e) {
		graph.add(0, Sets.newHashSet(e));
	}
	
	public void addParallel(Event e) {
		Set<Event> aux = graph.get(0);
		
		if(aux == null) {
			aux = Sets.newHashSet();
		}
		
		aux.add(e);
		graph.set(0, aux);
		
		aux = null;
	}
	
	public void addParallelGroup(Set<Event> group) {
		Set<Event> aux = Sets.newHashSet();
		
		graph.add(0, aux);
		
		for(Event e: group) {
			addParallel(e);
		}
		
		aux = null;
	}
	
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		
		result = prime * result + ((getGraph() == null) ? 0 : getGraph().hashCode());
		
		return result;
	}

	public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		
		if(obj == null) {
			return false;
		}
		
		if(getClass() != obj.getClass()) {
			return false;
		}
		
		Episode other = (Episode) obj;
		
		if(getGraph() == null) {
			if(other.getGraph() != null) {
				return false;
			}
		}
		else if(!getGraph().equals(other.getGraph())) {
			return false;
		}
		
		return true;
	}

	public String toString() {
		String res = getId() + " = [";
		
		for(Set<Event> labels: getGraph()) {
			res += "(";
			
			for(Event e: labels) {
				res += e.getId() + ", ";
			}
			
			res = res.substring(0, res.length() - 2) + ") --> ";
		}
		
		if(!isEmpty()) {
			res = res.substring(0, res.length() - 5);
		}
		
		res += "]";
		
		return res;
	}
}
